package cn.lingyangwl.agile.system.model.entity;

import cn.lingyangwl.agile.model.BasePlusPO;
import cn.lingyangwl.agile.model.constants.ValidationCons;
import cn.lingyangwl.agile.model.enums.BoolEnum;
import cn.lingyangwl.agile.model.module.dict.CusFieldBind;
import cn.lingyangwl.agile.model.module.dict.DictTypeCons;
import cn.lingyangwl.agile.system.constants.MenuCons;
import cn.lingyangwl.framework.tool.core.tree.TreeNode;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.*;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;

/**
 * 菜单权限表 sys_menu
 * @author shenguangyang
 */
@Getter
@Setter
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("sys_menu")
public class SysMenu extends BasePlusPO implements TreeNode<Long, SysMenu> {
    private static final long serialVersionUID = 1L;

    /** 菜单ID */
    @TableId
    private Long id;

    /** 菜单标识, 用于一些业务场景处理 */
    private String code;

    /** 菜单名称 */
    @NotEmpty(message = "菜单名称不能为空")
    @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
    private String name;

    /** 请求地址 */
    private String url;

    /** 父菜单ID */
    private Long parentId;

    /** 排序编号 */
    @NotNull(message = "排序编号")
    private Integer sortNum;

    /** 路由地址 */
    @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
    private String path;

    /** 组件路径 */
    @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
    private String component;

    /** 是否缓存（0缓存 1不缓存） */
    private Boolean isCache;

    /**
     * 类型（M目录 C菜单 F按钮）
     * @see MenuCons.Type
     */
    @NotEmpty(message = "菜单类型不能为空")
    @CusFieldBind(type = DictTypeCons.MENU_TYPE, target = "menuTypeText")
    private String menuType;

    /** 绑定显示属性，非表字典（排除） */
    @TableField(exist = false)
    private String menuTypeText;

    /**
     * 是否隐藏路由菜单: 0否,1是（默认值0）
     */
    private Boolean hideMenu;

    /**
     * 是否隐藏tab
     */
    private Boolean hideTab;

    /**
     * 菜单状态
     * @see MenuCons
     */
    private String status;

    /**
     * 菜单权限编码，例如：“sys:schedule:list,sys:schedule:info”,多个逗号隔开
     */
    @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
    private String perms;

    /**
     * 权限策略1显示2禁用
     */
    private String permsType;

    /**
     * 一级菜单跳转地址
     */
    private String redirect;

    /** 菜单图标 */
    private String icon;

    /**
     * 是否路由菜单
     */
    private Boolean route;

    /**
     * 是否为聚合路由 (聚合路由的情况下允许使用子菜单路径作为父菜单的路由地址)
     */
    private Boolean alwaysShow;

    /**
     * 是否为外链
     */
    private Boolean external;

    /**
     * 场景id
     */
    @NotNull(message = ValidationCons.NOT_EMPTY)
    private Long sceneId;

    /**
     * 菜单的拷贝id, 被拷贝和拷贝的id一样
     */
    private Long copyId;

    /**
     * 是否在主框架外打开
     */
    private Boolean isMainOut;

    /**
     * 是否为树的叶子节点
     */
    @TableField(exist = false)
    private String treeLeaf = BoolEnum.FALSE.getCode();

    /** 子菜单 */
    @TableField(exist = false)
    @Builder.Default
    private List<SysMenu> children = new ArrayList<>();

    public static LambdaQueryWrapper<SysMenu> lqw() {
        return Wrappers.lambdaQuery();
    }

    public static LambdaUpdateWrapper<SysMenu> luw() {
        return Wrappers.lambdaUpdate();
    }

    @Override
    public Long treeId() {
        return this.id;
    }

    @Override
    public void treeId(Long id) {
        this.id = id;
    }

    @Override
    public Long treeParentId() {
        return this.parentId;
    }

    @Override
    public void treeParentId(Long parentId) {
        this.parentId = parentId;
    }

    @Override
    public List<SysMenu> children() {
        return this.children;
    }

    @Override
    public String name() {
        return this.name;
    }

    @Override
    public void children(List<SysMenu> children) {
        this.children = children;
    }

    @Override
    public Integer sortNo() {
        return this.sortNum;
    }

    @Override
    public void treeLeaf(Boolean treeLeaf) {
        this.treeLeaf = (treeLeaf ? BoolEnum.TRUE: BoolEnum.FALSE).getCode();
    }
}
